var IForce = function(config) {
	var container, myChart, option, nodes, links, legendData, categories, depth = 0;
	var echartspath, renderToId, data;

	function init() {
		require.config({
			paths : {
				echarts : echartspath
			}
		});
		require([ 'echarts', 'echarts/chart/force', 'echarts/chart/chord' ],
				function(ec) {
					container = document.getElementById(renderToId);

					myChart = ec.init(container);

					myChart.showLoading({
						effect : 'bubble',
						textStyle : {
							fontWeight : 'bold',
							fontFamily : "Microsoft YaHei",
						}
					});

					option = cOption();

					myChart.setOption(option);

					setTimeout(function() {
						myChart.hideLoading();
					}, 1000);
				});
	}

	function cOption() {
		sLegendData();
		sCategories();
		sNodes();
		sLinks();

		return {
			title : {
				text : 'Echarts Force（左树型）',
				subtext : 'Echarts Force-directed tree',
				x : 'right',
				y : 'bottom'
			},
			tooltip : {
				trigger : 'item',
				formatter : '{b}'
			},
			toolbox : {
				show : true,
				feature : {
					restore : {
						show : true
					},
					saveAsImage : {
						show : true
					}
				}
			},
			legend : {
				x : 'left',
				orient : 'vertical',
				data : legendData
			},
			series : [ {
				type : 'force',
				name : "",
				ribbonType : false,
				categories : categories,
				itemStyle : {
					normal : {
						label : {
							show : true,
							textStyle : {
								color : '#333'
							}
						},
						nodeStyle : {
							brushType : 'both',
							borderColor : 'rgba(255,215,0,0.4)',
							borderWidth : 1
						},
						linkStyle : {
							type : 'line'
						}
					}
				},
				minRadius : 8,
				maxRadius : 15,
				linkSymbol : 'arrow',
				nodes : nodes,
				links : links,
			} ]
		};
	}

	function sLegendData() {
		legendData = [ gDisplayName(data) ];
		for ( var i = 0; i < data.children.length; i++) {
			var ch = data.children[i];
			legendData.push(gDisplayName(ch));
		}
	}

	function sCategories() {
		categories = [ {
			name : gDisplayName(data)
		} ];
		for ( var i = 0; i < data.children.length; i++) {
			var ch = data.children[i];
			categories.push({
				name : gDisplayName(ch)
			});
		}
	}

	function sNodes() {
		nodes = [ cNode(data, 0, 15, 0) ];

		for ( var i = 0; i < data.children.length; i++) {
			var ch = data.children[i];
			var n = cNode(ch, nodes.length, 10, (i + 1));
			nodes.push(n);
			loop(ch, n);
		}

		function loop(owlEntity, parentNode) {
			for ( var i = 0; i < owlEntity.children.length; i++) {
				var ch = owlEntity.children[i];
				var value = parentNode.value - parentNode.depth - 2;
				value = value <= 0 ? 2 : value;
				var n = cNode(ch, nodes.length, value, parentNode.category);
				nodes.push(n);
				loop(ch, n);
			}
		}
	}

	function cNode(owlEntity, id, value, category) {
		var node = {
			name : gIri(owlEntity),
			iri : gIri(owlEntity),
			label : gDisplayName(owlEntity),
			fixX : true,
			depth : owlEntity.depth,
			initial : getInitial(owlEntity.depth),
			id : id,
			value : value,
			category : category
		};

		if (owlEntity.entityType == 'NAMED_INDIVIDUAL') {
			node.symbol = 'diamond';
		}

		var name = "";

		for ( var i = 0; i < owlEntity.propertyValues.length; i++) {
			var pv = owlEntity.propertyValues[i];
			if (!pv.logical && pv.name != "rdfs:label") {
				name += pv.name + " " + pv.value + " ";
			}
		}

		if (name.trim() != "") {
			node.name = name;
		}

		return node;
	}

	function sLinks() {
		links = [];

		loop(data);

		function loop(owlEntity) {
			sImpliedLink(owlEntity);
			for ( var i = 0; i < owlEntity.children.length; i++) {
				var ch = owlEntity.children[i];

				var link = cLink(owlEntity, ch);

				links.push(link);

				loop(ch);
			}
		}
	}

	function cLink(source, target) {
		var sourceID = 0, targetID = 0, weight = 0, name = '';

		var sF = false, tF = false;
		for ( var i = 0; i < nodes.length; i++) {
			if (nodes[i].iri == source.iri) {
				sourceID = nodes[i].id;
				sF = true;
			}

			if (nodes[i].iri == target.iri) {
				targetID = nodes[i].id;
				weight = nodes[i].depth;
				if (nodes[i].symbol) {
					name = 'hasInstance';
				} else {
					name = 'hasChildren';
				}
				tF = true;
			}
			if (sF && tF) {
				break;
			}
		}

		var link = {
			source : sourceID,
			target : targetID,
			weight : weight,
			name : name
		};

		return link;
	}

	function sImpliedLink(owlEntity) {
		for ( var i = 0; i < owlEntity.propertyValues.length; i++) {
			var pv = owlEntity.propertyValues[i];
			if (pv.logical) {
				var sourceID = -1, targetID = -1, weight = -1, name = "";

				var sF = false, tF = false;
				for ( var i = 0; i < nodes.length; i++) {
					if (nodes[i].iri == gIri(owlEntity)) {
						sourceID = nodes[i].id;
						sF = true;
					}

					if (nodes[i].iri == pv.value) {
						targetID = nodes[i].id;
						weight = nodes[i].depth;
						tF = true;
					}
					if (sF && tF) {
						break;
					}
				}

				if (!sF) {
					var node = cNode(owlEntity, nodes.length, 10, 0);
					nodes.push(node);
					sourceID = node.id;
				}

				if (!tF) {
					var newOwlEntity = {
						iri : pv.value,
						displayName : pv.name,
						entityType : '',
						propertyValues : [],
						children : []
					};
					var node = cNode(newOwlEntity, nodes.length, 10, 0);
					nodes.push(node);
					targetID = node.id;
					weight = 1;
				}

				name = pv.name ? pv.name : "hasObjectProperty";

				var link = {
					source : sourceID,
					target : targetID,
					weight : weight,
					name : name
				};

				links.push(link);
			}
		}
	}

	function getInitial(dep) {
		var x = (container.clientWidth - 20) * dep / (depth + 1) + 25;
		var y = container.clientHeight / 2 + (1 - Math.random()) * 200;
		return [ x, y ];
	}

	function gDisplayName(owlEntity) {
		return owlEntity.displayName ? owlEntity.displayName : "UnKnow";
	}

	function gIri(owlEntity) {
		return owlEntity.iri ? owlEntity.iri : "UnKonw";
	}

	function setDepth() {

		function mock(node, dep) {
			node.depth = dep;

			if (dep > depth) {
				depth = dep;
			}

			for ( var i = 0; i < node.children.length; i++) {
				var ch = node.children[i];
				mock(ch, dep + 1);
			}

		}

		mock(data, 0);

	}

	this.draw = function() {
		echartspath = config.echartspath;
		renderToId = config.renderToId;
		data = config.data;

		setDepth();

		init();
	};
};